package com.capinfo.commons.project.model.security;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.capinfo.components.security.model.SecureResource;
import com.capinfo.framework.model.PositionalEntity;

/**
 * <p>
 * 应用可用资源的声明表，用来暴露应用中的功能
 * </p>
 * 
 * @author
 * 
 * 
 */
@Entity
@Table(name="SYSTEM_RESOURCES")
@SequenceGenerator(name="seqResources",sequenceName="SEQ_RESOURCES", allocationSize=1)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class SystemResource implements SecureResource<SystemResource, SystemRole, SystemViewStamp>, PositionalEntity {
	
	private Long rootId = Long.valueOf(1);
  
	private Long id;

	// 上级
	private Long parentId;
	private SystemResource parent;

	// 名称
	private String name;

	// 资源的作用的类型（默认为"URL"）
	private String type = "URL";

	// 资源的值（一般为访问的URL)
	private String value;

	//指定资源在view层是否显示时，用于security标签中的声明。
	private Long viewStampId;
	private SystemViewStamp viewStamp;

	// 资源排列的顺序
	private Integer position;

	// 是否打开在右侧panel 1-打开 0-不打开。
	private Boolean viewInRightPanel = true;

	// 是否可显示 1-可显示 0-不显示。
	private boolean display = true;

	// 是否需要授权才可访问 1-需要 0-不需要。
	private boolean needAuthorized = true;
	
	// 是否为分类菜单 
	private boolean categoryMenu = false;

	// 关联角色。
	private Set<SystemRole> roles = new HashSet<SystemRole>();
	
	// 下级
	private List<SystemResource> children = new ArrayList<SystemResource>();

	
	public SystemResource() {
	}

	@Id	
	@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="seqResources") 
    @Column(name="ID", unique=true, nullable=false, precision=10, scale=0)
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@Column(name="NAME", length=120)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Column(name="PARENT_ID", precision=10, scale=0)
	public Long getParentId() {
		return parentId;
	}

	public void setParentId(Long parentId) {
		this.parentId = parentId;
	}

	@ManyToOne(targetEntity=SystemResource.class, cascade=CascadeType.MERGE, fetch=FetchType.LAZY)
	@JoinColumn(name="PARENT_ID",insertable=false,updatable=false)
	public SystemResource getParent() {
		return parent;
	}

	public void setParent(SystemResource parent) {
		this.parent = parent;
	}

	@OneToMany(targetEntity=SystemResource.class, cascade=CascadeType.ALL)
	@JoinColumn(name="PARENT_ID")
	@OrderBy(value="position asc")
	public List<SystemResource> getChildren() {
		return children;
	}
	public void setChildren(List<SystemResource> children) {
		this.children = children;
	}

	@Column(name="DISPLAY", precision=1, scale=0)
	public boolean isDisplay() {
		return display;
	}

	public void setDisplay(boolean display) {
		this.display = display;
	}

	@Column(name="IS_NEED_AUTHORIZED", precision=1, scale=0)
	public boolean isNeedAuthorized() {
		return needAuthorized;
	}

	public void setNeedAuthorized(boolean needAuthorized) {
		this.needAuthorized = needAuthorized;
	}

	/**
	 * 是否为分类菜单 
	 */
	@Column(name="IS_CATEGORY_MENU", precision=1, scale=0)
	public boolean isCategoryMenu() {
		return categoryMenu;
	}

	public void setCategoryMenu(boolean categoryMenu) {
		this.categoryMenu = categoryMenu;
	}

	@Column(name="POSITION", precision=5, scale=0)
	public Integer getPosition() {
		return position;
	}

	public void setPosition(Integer position) {
		this.position = position;
	}

	@ManyToMany(targetEntity=SystemRole.class, cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
	@Fetch(FetchMode.SUBSELECT)
	@JoinTable(name="SYSTEM_RESOURCES_ROLES", joinColumns={@JoinColumn(name="RESOURCE_ID")},inverseJoinColumns={@JoinColumn(name="ROLE_ID")})
	public Set<SystemRole> getRoles() {
		return roles;
	}

	public void setRoles(Set<SystemRole> roles) {
		this.roles = roles;
	}

	@Column(name="TYPE", length=20)
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	@Column(name="VALUE", length=254)
	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}
	
	/**
	 * 指定资源在view层是否显示时，用于security标签中的声明。
	 * @return Long
	 * @author 
	 * <p><strong>Date:</strong>2015年10月27日下午4:17:10</p>
	 */
	@Column(name="VIEW_STAMP_ID", length=12)
	public Long getViewStampId() {
		return viewStampId;
	}

	public void setViewStampId(Long viewStampId) {
		this.viewStampId = viewStampId;
	}

	/**
	 * 指定资源在view层是否显示时，用于security标签中的声明。
	 */
	@ManyToOne(targetEntity = SystemViewStamp.class, fetch = FetchType.LAZY)
	@JoinColumn(name="VIEW_STAMP_ID", insertable = false, updatable = false)
    public SystemViewStamp getViewStamp() {
		return viewStamp;
	}

	public void setViewStamp(SystemViewStamp viewStamp) {
		this.viewStamp = viewStamp;
	}

	@Column(name="VIEW_IN_RIGHT_PANEL", precision= 1, scale=0)
	public Boolean getViewInRightPanel() {
		return viewInRightPanel;
	}

	public void setViewInRightPanel(Boolean viewInRightPanel) {
		this.viewInRightPanel = viewInRightPanel;
	}
	
	@Transient
	public Long getRootId() {
		return rootId;
	}
	
	@Transient
	public String getAuthorities(){
		String authorities = "";
		for( SystemRole role: getRoles()){
			authorities += "," + role.getName();
		}
		if( null != getViewStamp()){
			authorities += "," + getViewStamp().getName();
		}
		
		if( authorities.length() > 0 ){
			authorities = authorities.substring(1);
		}
		
		return authorities;
	}
	
	@Transient
	public boolean getHasChildren(){
		
		return !getChildren().isEmpty();
	}

	public boolean equals(Object other) {

		if ((this == other))
			return true;
		if (!(other instanceof SystemResource))
			return false;

		SystemResource castOther = (SystemResource) other;
		return new EqualsBuilder().append(this.getId(), castOther.getId())
		// .append(this.getName(), castOther.getName())
				.isEquals();
	}

	public int hashCode() {

		return new HashCodeBuilder().append(getId())
		// .append(getName())
				.toHashCode();
	}
	
	@Override
	public String toString() {
		
		return new ToStringBuilder(this).append("id" , getId())
										.append("name" ,this.getName())
										.append("value",this.getValue()).toString(); 
	}


}